// Go作者版权所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package modload

import (
	"context"
	"errors"
	"os"
	"sort"

	"cmd/go/internal/modfetch"

	"golang.org/x/mod/module"
	"golang.org/x/mod/semver"
)

// cmpVersion实现模块加载器中版本的比较。
// None
// 它与semver一致。除了作为特例，
// 版本“”被视为高于所有其他版本。
// 主模块（也称为目标）没有版本，必须选择
// 模块依赖关系图中相同模块的其他版本。
func cmpVersion(v1, v2 string) int {
	if v2 == "" {
		if v1 == "" {
			return 0
		}
		return -1
	}
	if v1 == "" {
		return 1
	}
	return semver.Compare(v1, v2)
}

// mvsReqs实现模块语义版本的mvs.Reqs，
// 内部应用任何排除或替换。
type mvsReqs struct {
	roots []module.Version
}

func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
	if mod == Target {
		// 使用构建r时存在的构建列表，而不是当前列表
		// 全局构建列表。
		return r.roots, nil
	}

	if mod.Version == "none" {
		return nil, nil
	}

	summary, err := goModSummary(mod)
	if err != nil {
		return nil, err
	}
	return summary.require, nil
}

// Max根据semver.Compare返回v1和v2的最大值。
// None
// 作为特例，版本“”被视为高于所有其他版本
// 版本。主模块（也称为目标）没有版本，必须
// 可以在模块依赖关系中选择相同模块的其他版本
// 图表
func (*mvsReqs) Max(v1, v2 string) string {
	if cmpVersion(v1, v2) < 0 {
		return v2
	}
	return v1
}

// 升级是不可操作的，在这里实现mvs.Reqs。
// go-get-u的升级逻辑在../modget/get.go中。
func (*mvsReqs) Upgrade(m module.Version) (module.Version, error) {
	return m, nil
}

func versions(ctx context.Context, path string, allowed AllowedFunc) ([]string, error) {
	// 注意：modfetch.Lookup和repo.Versions被缓存，
	// 因此，我们没有必要在这里添加额外的缓存。
	var versions []string
	err := modfetch.TryProxies(func(proxy string) error {
		repo, err := lookupRepo(proxy, path)
		if err != nil {
			return err
		}
		allVersions, err := repo.Versions("")
		if err != nil {
			return err
		}
		allowedVersions := make([]string, 0, len(allVersions))
		for _, v := range allVersions {
			if err := allowed(ctx, module.Version{Path: path, Version: v}); err == nil {
				allowedVersions = append(allowedVersions, v)
			} else if !errors.Is(err, ErrDisallowed) {
				return err
			}
		}
		versions = allowedVersions
		return nil
	})
	return versions, err
}

// previousVersion返回紧跟在
// m、 版本，如果没有标记以前的版本，则版本为“无”。
// None
// 由于在版本列表中找不到目标的版本，
// 它没有以前的版本。
func previousVersion(m module.Version) (module.Version, error) {
	// TODO（golang.org/issue/38714）：通过MVS跟踪上下文的线程。

	if m == Target {
		return module.Version{Path: m.Path, Version: "none"}, nil
	}

	list, err := versions(context.TODO(), m.Path, CheckAllowed)
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			return module.Version{Path: m.Path, Version: "none"}, nil
		}
		return module.Version{}, err
	}
	i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) >= 0 })
	if i > 0 {
		return module.Version{Path: m.Path, Version: list[i-1]}, nil
	}
	return module.Version{Path: m.Path, Version: "none"}, nil
}

func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
	return previousVersion(m)
}
